package com.kantboot.functional.pay.wechat.service.impl;

import com.kantboot.business.water.balance.BusWaterBalanceCodeMenu;
import com.kantboot.business.water.domain.entity.BusWaterGoodsOrder;
import com.kantboot.business.water.service.IBusWaterGoodsOrderService;
import com.kantboot.business.water.service.IBusWaterGoodsService;
import com.kantboot.functional.pay.order.domian.entity.FunctionalPayOrder;
import com.kantboot.functional.pay.order.emit.PayEmit;
import com.kantboot.functional.pay.order.service.IFunctionalPayOrderService;
import com.kantboot.functional.pay.wechat.domain.entity.PayWechatPayParam;
import com.kantboot.functional.pay.wechat.service.IFunctionalPayWechatOrderService;
import com.kantboot.functional.pay.wechat.setting.WechatPaySetting;
import com.kantboot.functional.pay.wechat.util.*;
import com.kantboot.functional.third.party.wechat.service.ITpWechatService;
import com.kantboot.system.user.domain.dto.BalanceAddDTO;
import com.kantboot.system.user.service.ISysUserBalanceService;
import com.kantboot.util.common.exception.BaseException;
import jakarta.annotation.Resource;
import lombok.extern.log4j.Log4j2;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.List;

@Log4j2
@Service
public class FunctionalPayWechatOrderServiceImpl implements IFunctionalPayWechatOrderService {

    public static final String PAY_METHOD_CODE_WECHAT = "wechat";

    @Resource
    private WechatPaySetting wechatPaySetting;

    @Resource
    private IFunctionalPayOrderService payOrderService;

    @Resource
    private ITpWechatService tpWechatService;

    @Resource
    private IBusWaterGoodsOrderService waterGoodsOrderService;

    @Resource
    private ISysUserBalanceService sysUserBalanceService;

    @Resource
    private IBusWaterGoodsService goodsService;


    @Resource
    private PayEmit payEmit;


    @Override
    public WechatPayResult getPayResultByMp(Long orderId, String code) {
        WechatPayPlatformParam wechatPayPlatformParam = wechatPaySetting.getWechatPayPlatformParam();
        String appid = wechatPayPlatformParam.getMpAppid();
        String mchid = wechatPayPlatformParam.getMchid();
        String payNotifyURL = wechatPayPlatformParam.getPayNotifyURL();
        String payCertSerialNo = wechatPayPlatformParam.getPayCertSerialNo();
        // 获取支付订单
        FunctionalPayOrder unpaidById = payOrderService.getUnpaidById(orderId);
        PayWechatPayParam wechatPayParamDTO = new PayWechatPayParam();
        // 设置微信小程序的appid
        wechatPayParamDTO.setAppid(appid);
        // 设置商户号
        wechatPayParamDTO.setMchid(mchid);
        // 设置订单号
        wechatPayParamDTO.setOutTradeNo(orderId+"");
        // 设置金额
        wechatPayParamDTO.setAmountTotal(unpaidById.getAmount());
        // 设置币种
        wechatPayParamDTO.setAmountCurrency(unpaidById.getCurrency());
        // 设置交易说明
        wechatPayParamDTO.setDescription(unpaidById.getDescription());
        // 设置支付回调地址
        wechatPayParamDTO.setNotifyUrl(payNotifyURL+"/"+orderId);
        // 根据code获取openId
        String openIdByCodeInMp = tpWechatService.getOpenIdByCodeInMp(code);
        wechatPayParamDTO.setPayerOpenid(openIdByCodeInMp);
        // 更新支付方式
        payOrderService.updatePayMethodCodeById(orderId, PAY_METHOD_CODE_WECHAT);
        return wechatPayParamDTO.createResult(wechatPaySetting.getPayPrivateKey(),payCertSerialNo);
    }


    @Override
    public FunctionalPayOrder handleWechatPay(String orderId) {
        // 查询orderId是否已被处理
//        FunctionalPayOrder functionalPayOrder = payOrderService.getById(Long.parseLong(orderId));
        // TODO 之后再打开，这个项目不处理
        // 如果已被处理，直接返回
//        if (byId.getIsStatusProcessed()) {
//            return byId;
//        }

        WechatPayPlatformParam wechatPayPlatformParam = wechatPaySetting.getWechatPayPlatformParam();
        String mchid = wechatPayPlatformParam.getMchid();
        String payCertSerialNo = wechatPayPlatformParam.getPayCertSerialNo();

        // 根据订单号查询订单
        WechatOrderByOutTradeNoResult result  =
                new WechatOrderByOutTradeNoParam()
                        .setMchid(mchid)
                        .setOutTradeNO(orderId)
                        .toResult(wechatPayPlatformParam.getPayPrivateKey(), payCertSerialNo);

        // 如果是未支付状态，更新为未支付状态
        if("NOTPAY".equals(result.getTradeState())) {
            payOrderService.updateStatusCodeById(Long.parseLong(orderId), FunctionalPayOrder.STATUS_CODE_UNPAID);
        }

        // 如果是支付成功状态，更新为支付成功状态
        if("SUCCESS".equals(result.getTradeState())) {

            payOrderService.updateStatusCodeById(Long.parseLong(orderId), FunctionalPayOrder.STATUS_CODE_PAID);
            waterGoodsOrderService.updateOrderPaySuccessEvent(orderId);
            BusWaterGoodsOrder goodsOrder=waterGoodsOrderService.getByPayOrderId(Long.parseLong(orderId));
            // 查询goodsOrder是否是已支付
            if(FunctionalPayOrder.STATUS_CODE_PAID.equals(goodsOrder.getOrderStatusCode())) {
                throw BaseException.of("orderAlreadyPaid", "订单已支付");
            }

            // 给商品添加销量
            goodsService.addSalesVolume(goodsOrder.getGoodsId(), goodsOrder.getGoodsNumber());


            // 给消费者加上对应的消费积分和消费金额
            Long userIdOfConsumer = goodsOrder.getUserIdOfConsumer();
            BalanceAddDTO balanceAddDTO = new BalanceAddDTO();
            balanceAddDTO.setUserId(userIdOfConsumer);
            balanceAddDTO.setBalanceCode(BusWaterBalanceCodeMenu.BALANCE_CODE_INTEGRAL);
            balanceAddDTO.setReasonCode("goodsOrder");
            if(goodsOrder.getIntegral()!=null){
                balanceAddDTO.setNumber(BigDecimal.valueOf(goodsOrder.getIntegral()));
            }else{
                balanceAddDTO.setNumber(BigDecimal.valueOf(goodsOrder.getPayMoney().intValue()));
            }
            sysUserBalanceService.changeBalance(balanceAddDTO);

            // 添加总消费额
            BalanceAddDTO balanceAddDTO2 = new BalanceAddDTO();
            balanceAddDTO2.setUserId(userIdOfConsumer);
            balanceAddDTO2.setBalanceCode(BusWaterBalanceCodeMenu.BALANCE_CODE_TOTAL_CONSUMPTION);
            balanceAddDTO2.setReasonCode("goodsOrder");
            balanceAddDTO2.setNumber(goodsOrder.getPayMoney());
            sysUserBalanceService.changeBalance(balanceAddDTO2);


            // 添加月消费额
            BalanceAddDTO balanceAddDTO3 = new BalanceAddDTO();
            balanceAddDTO3.setUserId(userIdOfConsumer);
            balanceAddDTO3.setBalanceCode(BusWaterBalanceCodeMenu.BALANCE_CODE_MONTH_CONSUMPTION);
            balanceAddDTO3.setReasonCode("goodsOrder");
            balanceAddDTO3.setNumber(goodsOrder.getPayMoney());
            sysUserBalanceService.changeBalance(balanceAddDTO3);

        }

        FunctionalPayOrder order = payOrderService.getById(Long.parseLong(orderId));
        payEmit.emit(order);
        return order;
    }

    @Override
    public FunctionalPayOrder refundByOrder(String orderId) {
        WechatPayPlatformParam wechatPayPlatformParam = wechatPaySetting.getWechatPayPlatformParam();
        String mchid = wechatPayPlatformParam.getMchid();
        String payCertSerialNo = wechatPayPlatformParam.getPayCertSerialNo();
        String payPrivateKey = wechatPaySetting.getPayPrivateKey();

        // 根据订单id获取金额
        FunctionalPayOrder byId = payOrderService.getById(Long.parseLong(orderId));

        // 如果订单状态不是已退款，抛出异常
        if(FunctionalPayOrder.STATUS_CODE_REFUNDED.equals(byId.getStatusCode())) {
            throw BaseException.of("orderAlreadyRefunded", "订单已退款");
        }


        // 退款金额，单位为分，因为数据库的金额是元，所以要乘以100
        Long refund = byId.getAmount().multiply(new BigDecimal(100)).longValue();


        // 退款，之后国际化项目时，需要将金额转换为对应的币种
        // 此处为了方便，订单号和退款单号都为订单号,这个项目中，不做太多处理
        WechatRefundsParam wechatRefundsParam = new WechatRefundsParam()
                .setOutTradeNo(orderId)
                .setOutRefundNo(orderId)
                .setAmount(new WechatRefundsParam.Amount()
                        .setTotal(refund)
                        .setRefund(refund)
                        .setCurrency(byId.getCurrency())
                );

        // 生成退款结果
        WechatRefundsResult wechatRefundsResult = wechatRefundsParam.createResult(payPrivateKey, payCertSerialNo, mchid);
        FunctionalPayOrder functionalPayOrder = handleWechatRefund(orderId, wechatRefundsResult);
        payEmit.emit(functionalPayOrder);
        return functionalPayOrder;
    }

    @Override
    public FunctionalPayOrder handleWechatRefund(String orderId, WechatRefundsResult wechatRefundsResult) {
        if(WechatRefundsResult.STATUS_SUCCESS.equals(wechatRefundsResult.getStatus())) {
            // 如果退款成功，更新订单状态为已退款
            payOrderService.updateStatusCodeById(Long.parseLong(orderId), FunctionalPayOrder.STATUS_CODE_REFUNDED);
        }
        else if(WechatRefundsResult.STATUS_PROCESSING.equals(wechatRefundsResult.getStatus())) {
            // 如果退款处理中，更新订单状态为退款中
            payOrderService.updateStatusCodeById(Long.parseLong(orderId), FunctionalPayOrder.STATUS_CODE_REFUNDING);
        }
        else if(WechatRefundsResult.STATUS_CLOSED.equals(wechatRefundsResult.getStatus())) {
            // 如果退款关闭，更新订单状态为已支付
            payOrderService.updateStatusCodeById(Long.parseLong(orderId), FunctionalPayOrder.STATUS_CODE_PAID);
        }
        else if(WechatRefundsResult.STATUS_ABNORMAL.equals(wechatRefundsResult.getStatus())) {
            // 如果退款异常，更新订单状态为异常
            payOrderService.updateStatusCodeById(Long.parseLong(orderId), FunctionalPayOrder.STATUS_CODE_ERROR);
        }
        FunctionalPayOrder order = payOrderService.getById(Long.parseLong(orderId));
        return order;
    }

    @Override
    public WechatRefundsResult queryWechatRefund(String orderId) {
        WechatPayPlatformParam wechatPayPlatformParam = wechatPaySetting.getWechatPayPlatformParam();
        String mchid = wechatPayPlatformParam.getMchid();
        String payCertSerialNo = wechatPayPlatformParam.getPayCertSerialNo();
        String payPrivateKey = wechatPaySetting.getPayPrivateKey();


        // 根据订单id获取金额
        FunctionalPayOrder byId = payOrderService.getById(Long.parseLong(orderId));

        // 退款，之后国际化项目时，需要将金额转换为对应的币种
        // 此处为了方便，订单号和退款单号都为订单号,这个项目中，不做太多处理
        WechatRefundsParam wechatRefundsQueryParam = new WechatRefundsParam()
                .setOutTradeNo(orderId)
                .setOutRefundNo(orderId);

        // 生成退款结果
        return wechatRefundsQueryParam.queryResult(payPrivateKey, payCertSerialNo, mchid);
    }

    @Override
    public void refreshOrderTaskStatus() {
        //检查未支付的订单主动查询是否已经支付
        List<FunctionalPayOrder> payOrders=payOrderService.queryUnPayOrder();
        for (FunctionalPayOrder payOrder : payOrders) {
            handleWechatPay(String.valueOf(payOrder.getId()));
        }

    }

}
